/**
 * @file birth_time.cpp
 * @brief Brief description of birth_time.cpp
 * @author achdu0000@163.com
 * @version 1.0.0
 * @date 2024/07/07
 */

#include "birth_time.h"
#include "../meridian_time/meridian_time.h"

// ==================================================
// =============== PRE-DECLARE ======================
// ==================================================

LV_IMG_DECLARE(img_icon_people_with_heart_50x50)
LV_IMG_DECLARE(img_icon_people_20x20)

LV_FONT_DECLARE(lv_font_yahei_bold_10)
LV_FONT_DECLARE(lv_font_yahei_bold_12)
LV_FONT_DECLARE(lv_font_yahei_bold_16)
LV_FONT_DECLARE(lv_font_yahei_bold_20)

extern lv_color_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(170, 200)];

// ==================================================
// =============== DEFINATIONS ======================
// ==================================================

#define CANVAS_WIDTH 120
#define CANVAS_HEIGHT 50

// ==================================================
// =============== STATIC VARIABLES =================
// ==================================================

static lv_color_t circle_color = lv_color_make(255, 0, 0);

lv_obj_t *health_and_temperature_label = nullptr;
static lv_obj_t *icon_people_with_heart_obj = nullptr;

static uint16_t birth_year_val;
static uint8_t birth_month_val;
static uint8_t birth_day_val;
static uint8_t birth_hour_val;
static uint8_t birth_min_val;
static const char *birth_year_ganzhi_str_val;
static const char *birth_jieqi_str_val;
static uint8_t birth_wuhou_index_val;

static uint16_t body_temperature_val;
static uint16_t body_blood_press_h_val;
static uint16_t body_blood_press_l_val;
static uint8_t body_blood_oxygen_val;
static uint8_t body_heart_rate_val;
static uint16_t body_walk_step_val;

static const char *body_state_str = nullptr;

static const char *day_ganzhi_str = nullptr;

static uint8_t yin_val;
static uint8_t yang_val;

// ==================================================
// =============== STATIC FUNCTION ==================
// ==================================================

/**
 * draw the sin curve on the canvas in lvgl
 * usually used by draw the psi curve
 *
 * @param canvas                    the canvas to draw
 * @param start_x                   the x coord of start point on canvas
 * @param start_y                   the x coord of start point on canvas
 * @param width                     the max width of curve
 * @param height                    the max height of curve
 * @param line_color                the color of curve
 * @param line_width                the width of curve (default = 1)
 * @param extra_period              the extra period (default = 1)
 * @note the param `extra_period`, 1 means 1 period(2 pi), x(x>1) means (1+1/x) period (2 pi + (2 pi) *(1/x))
 *
 * @return                          true if success
 */
inline static bool draw_trigo_sin_curve(lv_obj_t *canvas, lv_coord_t start_x, lv_coord_t start_y, lv_coord_t width, lv_coord_t height, lv_color_t line_color, uint8_t line_width = 1, uint8_t extra_period = 1);

// ==================================================
// =============== IMPLEMENTATION ===================
// ==================================================

bool set_birth_time_val(uint16_t birth_year, uint8_t birth_month, uint8_t birth_day, uint8_t birth_hour, uint8_t birth_min, const char *birth_year_ganzhi_str, const char *birth_jieqi_str, uint8_t birth_wuhou_index)
{
    birth_year_val = birth_year;
    birth_month_val = birth_month;
    birth_day_val = birth_day;
    birth_hour_val = birth_hour;
    birth_min_val = birth_min;
    birth_year_ganzhi_str_val = birth_year_ganzhi_str;
    birth_jieqi_str_val = birth_jieqi_str;
    birth_wuhou_index_val = birth_wuhou_index;
    return true;
}

bool set_body_temperature_val(uint16_t body_temperature)
{
    body_temperature_val = body_temperature;
    return true;
}

bool set_body_blood_press_val(uint8_t body_blood_press_h, uint8_t body_blood_press_l)
{
    body_blood_press_h_val = body_blood_press_h;
    body_blood_press_l_val = body_blood_press_l;
    return true;
}

bool set_body_blood_oxygen_val(uint8_t body_blood_oxygen)
{
    body_blood_oxygen_val = body_blood_oxygen;
    return true;
}

bool set_body_heart_rate_val(uint8_t body_heart_rate)
{
    body_heart_rate_val = body_heart_rate;
    return true;
}

bool set_body_walk_step_val(uint16_t body_walk_step)
{
    body_walk_step_val = body_walk_step;
    return true;
}

bool set_body_state_str(const char *body_state)
{
    body_state_str = body_state;
    return true;
}

bool set_now_day_ganzhi(const char *day_ganzhi_s)
{
    day_ganzhi_str = day_ganzhi_s;
    return true;
}

bool set_body_yinyang_val(uint8_t yin_value, uint8_t yang_value)
{
    yin_val = yin_value;
    yang_val = yang_value;
    return true;
}

const char *get_now_day_ganzhi()
{
    return day_ganzhi_str;
}

bool create_basic_birth_circle_ui(lv_obj_t *parent, lv_coord_t radius)
{

    lv_coord_t border_width = 3;
    lv_obj_t *circle = lv_obj_create(parent);
    lv_obj_set_size(circle, radius * 2, radius * 2);
    lv_obj_set_style_border_color(circle, circle_color, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_width(circle, border_width, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_radius(circle, LV_RADIUS_CIRCLE, LV_PART_MAIN | LV_STATE_DEFAULT);

    lv_obj_set_style_bg_opa(circle, LV_OPA_TRANSP, LV_PART_MAIN | LV_STATE_DEFAULT);

    lv_obj_center(circle);

    return true;
}

bool create_basic_icon_people_with_heart_ui(lv_obj_t *parent, uint16_t zoom)
{
    lv_obj_t *img = lv_img_create(parent);
    lv_img_set_src(img, &img_icon_people_with_heart_50x50);
    lv_img_set_zoom(img, zoom);
    lv_obj_center(img);
    icon_people_with_heart_obj = img;
    return true;
}

bool create_extend_2_body_health_param_info_ui(lv_obj_t *parent, lv_coord_t x_ofs, lv_coord_t y_ofs)
{
    lv_obj_t *text_label = lv_label_create(parent);
    lv_label_set_text(text_label, "【体温】\n【血压】\n【血氧】\n【心率】\n【日步数】");
    lv_obj_set_style_text_align(text_label, LV_TEXT_ALIGN_RIGHT, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_font(text_label, &lv_font_yahei_bold_12, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(text_label, lv_color_make(153, 102, 0), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_line_space(text_label, 5, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_align_to(text_label, parent, LV_ALIGN_CENTER, x_ofs, y_ofs);

    health_and_temperature_label = lv_label_create(parent);
    lv_label_set_text_fmt(health_and_temperature_label, "%d.%d\n%d/%d\n%d\n%d\n%d",
                          body_temperature_val / 10, body_temperature_val % 10,
                          body_blood_press_h_val, body_blood_press_l_val,
                          body_blood_oxygen_val,
                          body_heart_rate_val,
                          body_walk_step_val);
    lv_obj_set_style_text_align(health_and_temperature_label, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_font(health_and_temperature_label, &lv_font_yahei_bold_12, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(health_and_temperature_label, lv_color_make(255, 0, 0), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_line_space(health_and_temperature_label, 5, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_align_to(health_and_temperature_label, text_label, LV_ALIGN_OUT_RIGHT_MID, -3, 0);

   lv_obj_t *state_label = lv_label_create(parent);
    lv_label_set_text_fmt(state_label, "【当前体态】\n%s", body_state_str);
    lv_obj_set_style_text_align(state_label, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_font(state_label, &lv_font_yahei_bold_12, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(state_label, lv_color_make(0, 0, 204), LV_PART_MAIN | LV_STATE_DEFAULT);
    // lv_obj_set_style_text_line_space(state_label, 5, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_align_to(state_label, text_label, LV_ALIGN_OUT_BOTTOM_MID, 10, 5);

    return true;
}

lv_obj_t *get_basic_icon_people_with_heart_obj()
{
    return icon_people_with_heart_obj;
}

inline static bool draw_trigo_sin_curve(lv_obj_t *canvas, lv_coord_t start_x, lv_coord_t start_y, lv_coord_t width, lv_coord_t height, lv_color_t line_color, uint8_t line_width, uint8_t extra_period)
{
    lv_coord_t deg = (extra_period == 1 ? 360 : 360 + 360 / extra_period);
    /* then each px stands deg/width degrees */
    for (lv_coord_t x = 0; x < width; x++)
    {
        lv_coord_t x_deg = x * deg / width;
        for (uint8_t i = 0; i < line_width; i++)
        {
            lv_coord_t y = (height / 2 - i) * lv_trigo_sin(x_deg) / LV_TRIGO_SIN_MAX;
            y = height / 2 - y;

            lv_canvas_set_px_color(canvas, start_x + x, start_y + y, line_color);
            lv_canvas_set_px_opa(canvas, start_x + x, start_y + y, LV_OPA_COVER);
        }
    }
    return true;
}

bool create_extend_2_body_psi_ui_with_canvas(lv_obj_t *parent, lv_obj_t *canvas, lv_coord_t c_start_x, lv_coord_t c_start_y, lv_coord_t c_use_w, lv_coord_t c_use_h)
{
    /* draw the white base line */
    lv_draw_line_dsc_t line_dsc;
    lv_draw_line_dsc_init(&line_dsc);
    line_dsc.color = lv_color_white();
    line_dsc.opa = LV_OPA_COVER;
    line_dsc.width = 2;
    line_dsc.dash_width = 2;
    line_dsc.dash_gap = 5;

    static lv_point_t points[2];
    points[0].x = c_start_x;
    points[0].y = c_start_y;
    points[1].x = c_start_x + c_use_w;
    points[1].y = c_start_y;
    lv_canvas_draw_line(canvas, points, 2, &line_dsc);

    points[0].x = c_start_x;
    points[0].y = c_start_y + c_use_h;
    points[1].x = c_start_x + c_use_w;
    points[1].y = c_start_y + c_use_h;
    lv_canvas_draw_line(canvas, points, 2, &line_dsc);

    points[0].x = c_start_x;
    points[0].y = c_start_y + c_use_h / 2;
    points[1].x = c_start_x + c_use_w;
    points[1].y = c_start_y + c_use_h / 2;
    line_dsc.dash_width = 0;
    lv_canvas_draw_line(canvas, points, 2, &line_dsc);

    /* draw the p, s, i sin curve*/

    /* p */
    lv_color_t color = lv_color_make(255, 0, 0);
    draw_trigo_sin_curve(canvas, c_start_x + 3, c_start_y, c_use_w - 25, c_use_h, color, 3, 12);

    /* p label */
    uint8_t label_line_len = 7;
    uint8_t label_gap = 25;
    points[0].x = c_start_x;
    points[0].y = c_start_y + c_use_h * 3 / 4;
    points[1].x = points[0].x + label_line_len;
    points[1].y = points[0].y;

    line_dsc.color = color;
    lv_canvas_draw_line(canvas, points, 2, &line_dsc);

    static lv_draw_label_dsc_t label_dsc;
    lv_draw_label_dsc_init(&label_dsc);
    label_dsc.color = color;
    label_dsc.font = &lv_font_montserrat_12;
    lv_canvas_draw_text(canvas, points[1].x, points[1].y - 8, 100, &label_dsc, " P ");

    /* s */
    color = lv_color_make(84, 130, 53);
    draw_trigo_sin_curve(canvas, c_start_x + 6, c_start_y, c_use_w - 20, c_use_h, color, 3, 12);

    /* s label */

    points[0].x += label_gap;
    points[1].x = points[0].x + label_line_len;

    line_dsc.color = color;
    lv_canvas_draw_line(canvas, points, 2, &line_dsc);

    label_dsc.color = color;
    label_dsc.font = &lv_font_montserrat_12;
    lv_canvas_draw_text(canvas, points[1].x, points[1].y - 8, 100, &label_dsc, " S ");

    /* i */
    color = lv_color_make(0, 0, 204);
    draw_trigo_sin_curve(canvas, c_start_x + 9, c_start_y, c_use_w - 15, c_use_h, color, 3, 12);

    /* i label */

    points[0].x += label_gap;
    points[1].x = points[0].x + label_line_len;

    line_dsc.color = color;
    lv_canvas_draw_line(canvas, points, 2, &line_dsc);

    label_dsc.color = color;
    label_dsc.font = &lv_font_montserrat_12;
    lv_canvas_draw_text(canvas, points[1].x, points[1].y - 8, 100, &label_dsc, " I ");

    /* draw the icon people to show the current psi */
    lv_obj_t *img = lv_img_create(parent);
    lv_img_set_src(img, &img_icon_people_20x20);
    lv_obj_align_to(img, canvas, LV_ALIGN_DEFAULT, c_start_x + 5 + get_day_val() * (c_use_w - 30) / 31, c_start_y + c_use_h / 2 - img_icon_people_20x20.header.h / 2);

    return true;
}

bool create_extend_2_day_ganzhi_label_ui(lv_obj_t *parent, lv_coord_t x_ofs, lv_coord_t y_ofs)
{
    lv_obj_t *label = lv_label_create(parent);
    lv_label_set_text_fmt(label, "【人时-日】%s", get_now_day_ganzhi());
    lv_obj_set_style_text_font(label, &lv_font_yahei_bold_12, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(label, lv_color_make(112, 48, 160), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_align_to(label, parent, LV_ALIGN_CENTER, x_ofs, y_ofs);
    return true;
}

bool create_extend_2_guide_text_label_ui(lv_obj_t *parent, lv_coord_t x_ofs, lv_coord_t y_ofs)
{
    const char *big_str = "眠";
    const char *small_str[4] = {"动", "学", "作", "食"};

    lv_obj_t *label_big = lv_label_create(parent);
    lv_label_set_text_fmt(label_big, "%s", big_str);
    lv_obj_set_style_text_font(label_big, &lv_font_yahei_bold_20, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(label_big, lv_color_black(), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_align(label_big, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_align_to(label_big, parent, LV_ALIGN_CENTER, x_ofs, y_ofs);

    lv_obj_t *label_small = lv_label_create(parent);
    lv_label_set_text_fmt(label_small, "%s·%s\n%s·%s", small_str[0], small_str[1], small_str[2], small_str[3]);
    lv_obj_set_style_text_font(label_small, &lv_font_yahei_bold_10, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(label_small, SCREEN_FG_COLOR, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_align(label_small, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_align_to(label_small, label_big, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);

    return true;
}

bool create_extend_2_body_yin_yang_ui_with_canvas(lv_obj_t *parent, lv_obj_t *canvas, lv_coord_t c_start_x, lv_coord_t c_start_y, lv_coord_t c_use_w, lv_coord_t c_use_h, lv_coord_t r)
{
    if (c_use_h < 2 * r)
        return false;
    lv_coord_t center_x = c_start_x + c_use_w / 2;
    lv_coord_t center_y = c_start_y + r;
    lv_coord_t quarter_1_y = c_start_y + r / 2;
    lv_coord_t quarter_3_y = c_start_y + r * 3 / 2;

    lv_coord_t half_r = r / 2;
    lv_coord_t quarter_half_r = r / 8;

    lv_color_t split_color = SCREEN_FG_COLOR;

    for (uint8_t angle = 0; angle <= 180; angle++)
    {
        lv_coord_t x_up = center_x + half_r * lv_trigo_sin(angle) / LV_TRIGO_SIN_MAX;
        lv_coord_t y_up = quarter_1_y - half_r * lv_trigo_cos(angle) / LV_TRIGO_SIN_MAX;

        lv_canvas_set_px_color(canvas, x_up, y_up, split_color);
        lv_canvas_set_px_opa(canvas, x_up, y_up, LV_OPA_COVER);

        lv_coord_t x_down = center_x - half_r * lv_trigo_sin(angle) / LV_TRIGO_SIN_MAX;
        lv_coord_t y_down = quarter_3_y - half_r * lv_trigo_cos(angle) / LV_TRIGO_SIN_MAX;

        lv_canvas_set_px_color(canvas, x_down, y_down, split_color);
        lv_canvas_set_px_opa(canvas, x_down, y_down, LV_OPA_COVER);
    }

    /* start_y + 2*r*(1- yang_val %) */
    lv_coord_t yang_y = c_start_y + (100 - yang_val) * r / 50;
    lv_coord_t yin_y = c_start_y + (100 - yin_val) * r / 50;

    for (lv_coord_t y = c_start_y; y < c_start_y + c_use_h; y++)
    {
        lv_coord_t left_x = -1;
        lv_coord_t split_x = -1;
        lv_coord_t right_x = -1;
        for (lv_coord_t x = c_start_x; x < c_start_x + c_use_w; x++)
        {
            if ((x - center_x) * (x - center_x) + (y - center_y) * (y - center_y) < r * r)
            {
                if (left_x == -1)
                {
                    left_x = x;
                }
                if (split_x == -1 && lv_canvas_get_px(canvas, x, y).full == split_color.full)
                {
                    split_x = x;
                }
                right_x = x;
            }
            if ((x - center_x) * (x - center_x) + (y - quarter_1_y) * (y - quarter_1_y) < quarter_half_r * quarter_half_r)
            {
                lv_canvas_set_px_color(canvas, x, y, get_yinyang_color(YIN));
                lv_canvas_set_px_opa(canvas, x, y, LV_OPA_COVER);
            }
            if ((x - center_x) * (x - center_x) + (y - quarter_3_y) * (y - quarter_3_y) < quarter_half_r * quarter_half_r)
            {
                lv_canvas_set_px_color(canvas, x, y, get_yinyang_color(YANG));
                lv_canvas_set_px_opa(canvas, x, y, LV_OPA_COVER);
            }
        }
        if (left_x == -1 || split_x == -1 || right_x == -1)
            continue;

        for (lv_coord_t i = left_x; y >= yang_y && i < split_x; i++)
        {
            if (lv_canvas_get_px(canvas, i, y).full != get_yinyang_color(YIN).full)
            {
                lv_canvas_set_px_color(canvas, i, y, get_yinyang_color(YANG));
                lv_canvas_set_px_opa(canvas, i, y, LV_OPA_COVER);
            }
        }
        for (lv_coord_t i = split_x + 1; y >= yin_y && i < right_x; i++)
        {
            if (lv_canvas_get_px(canvas, i, y).full != get_yinyang_color(YANG).full)
            {
                lv_canvas_set_px_color(canvas, i, y, get_yinyang_color(YIN));
                lv_canvas_set_px_opa(canvas, i, y, LV_OPA_COVER);
            }
        }
    }

    return true;
}

bool create_extend_2_body_yin_yang_label_ui(lv_obj_t *parent, lv_coord_t x_ofs, lv_coord_t y_ofs, lv_coord_t gap_in_x)
{
    lv_obj_t *yang_label = lv_label_create(parent);
    lv_label_set_text_fmt(yang_label, "阳\n%d", yang_val);
    lv_obj_set_style_text_font(yang_label, &lv_font_yahei_bold_16, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(yang_label, get_yinyang_color(YIN), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_align(yang_label, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_align_to(yang_label, parent, LV_ALIGN_CENTER, x_ofs - gap_in_x / 2, y_ofs);

    lv_obj_t *yin_label = lv_label_create(parent);
    lv_label_set_text_fmt(yin_label, "阴\n%d", yin_val);
    lv_obj_set_style_text_font(yin_label, &lv_font_yahei_bold_16, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(yin_label, get_yinyang_color(YANG), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_align(yin_label, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_align_to(yin_label, parent, LV_ALIGN_CENTER, x_ofs + gap_in_x / 2, y_ofs);

    return true;
}